{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Anything2Img 测试\n",
    "\n",
    "本 notebook 用于测试 `src/autocoder/common/anything2img.py` 模块的功能。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2025-01-05 12:22:15,060\tINFO worker.py:1564 -- Connecting to existing Ray cluster at address: 127.0.0.1:6379...\n",
      "2025-01-05 12:22:15,075\tINFO worker.py:1740 -- Connected to Ray cluster. View the dashboard at \u001b[1m\u001b[32m127.0.0.1:8265 \u001b[39m\u001b[22m\n",
      "2025-01-05 12:22:15,171\tINFO worker.py:1564 -- Connecting to existing Ray cluster at address: 127.0.0.1:6379...\n",
      "2025-01-05 12:22:15,176\tINFO worker.py:1582 -- Calling ray.init() again after it has already been called.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2025-01-05 12:22:15.033 | INFO     | byzerllm.utils.connect_ray:connect_cluster:48 - JDK 21 will be used (/Users/allwefantasy/.auto-coder/jdk-21.0.2.jdk/Contents/Home)...\n",
      "\n",
      "2025-01-05 12:22:15.145 | INFO     | byzerllm.utils.connect_ray:connect_cluster:48 - JDK 21 will be used (/Users/allwefantasy/.auto-coder/jdk-21.0.2.jdk/Contents/Home)...\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 导入必要的模块\n",
    "import os\n",
    "import byzerllm\n",
    "from autocoder.common import AutoCoderArgs\n",
    "from autocoder.common.anything2img import Anything2Img\n",
    "from loguru import logger\n",
    "\n",
    "# 初始化测试环境\n",
    "logger.remove()\n",
    "logger.add(lambda msg: print(msg), level=\"INFO\")\n",
    "\n",
    "# 创建测试输出目录\n",
    "test_output_dir = \"./test_output\"\n",
    "os.makedirs(test_output_dir, exist_ok=True)\n",
    "\n",
    "# 初始化 AutoCoderArgs\n",
    "args = AutoCoderArgs(\n",
    "    output=test_output_dir,\n",
    "    model=\"deepseek_chat\",\n",
    "    vl_model=\"qwen_vl\"\n",
    ")\n",
    "\n",
    "# 初始化 LLM\n",
    "llm = byzerllm.ByzerLLM.from_default_model(model=\"deepseek_chat\")\n",
    "vl_llm = byzerllm.ByzerLLM.from_default_model(model=\"qwen_vl\")\n",
    "llm.setup_sub_client(\"vl_model\", vl_llm)\n",
    "\n",
    "# 初始化 Anything2Img\n",
    "converter = Anything2Img(llm, args)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2025-01-05 12:22:43.572 | INFO     | autocoder.common.anything2img:to_markdown:143 - Analyzed ./test_output/002-auto-coder.chat-初级入门指南.pdf_page1.png\n",
      "\n",
      "2025-01-05 12:23:09.834 | INFO     | autocoder.common.anything2img:to_markdown:143 - Analyzed ./test_output/002-auto-coder.chat-初级入门指南.pdf_page2.png\n",
      "\n",
      "生成的 Markdown 内容:\n",
      "002-auto-coder.chat 初级入门指南\n",
      "我们在上一篇介绍了如何安装 auto-coder.chat 回 Windows: auto-coder.chat 安装指南\n",
      "MacOS/Linux 直接 pip install -U auto-coder 即可。测试过的 python 版本为：3.10/3.11\n",
      "初始化设置\n",
      "在 PowerShell/CMD 或者 VSCode 内置的 terminal 中输入如下指令（auto-coder.chat）：\n",
      "PS C: \\Users\\Administrator\\projects\\auto-coder> auto-coder.chat\n",
      "记得不要忘记了使用 conda activate auto-coder 切换到合适的环境虚拟环境哟。\n",
      "第一次运行，系统会自动要求你提供一个大模型供应商（你后续可以改，比如用本地的模型或者其他第三方模型），此时会弹出一个对话框：\n",
      "\n",
      "我们分别给了官网，你可以去官网注册一个账号，你可以用上下箭头来切换网站，最后用 Tab 键切换到 Ok 按钮，然后点击 Enter 回车键确认。\n",
      "\n",
      "假设我使用的是 Deepseek 官网，你应该和我一样，在 API Keys 页面创建好了一个 API Key：![一个包含两个选项的界面，选项分别是 '硅基互动' 和 'Deepseek 官方'，并提供 Ok 和 Cancel 按钮。](./test_output/_images/cropped_002-auto-coder.chat-初级入门指南.pdf_page2.png)\n",
      "\n",
      "另外你可以冲比如一两块钱，这样你就用可用的 Token 数余额了：\n",
      "Markdown 文件已保存到: ./test_output/output.md\n"
     ]
    }
   ],
   "source": [
    "# 测试 Markdown 生成\n",
    "pdf_file = \"/Users/allwefantasy/Downloads/002-auto-coder.chat-初级入门指南.pdf\"\n",
    "markdown_content = converter.to_markdown(pdf_file, size=2)\n",
    "print(\"生成的 Markdown 内容:\")\n",
    "print(markdown_content)\n",
    "\n",
    "# 保存 Markdown 文件\n",
    "output_md = os.path.join(test_output_dir, \"output.md\")\n",
    "with open(output_md, \"w\", encoding=\"utf-8\") as f:\n",
    "    f.write(markdown_content)\n",
    "print(f\"Markdown 文件已保存到: {output_md}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 测试 PDF 转换"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "转换后的图片路径: ['./test_output/002-auto-coder.chat-初级入门指南.pdf_page1.png', './test_output/002-auto-coder.chat-初级入门指南.pdf_page2.png', './test_output/002-auto-coder.chat-初级入门指南.pdf_page3.png', './test_output/002-auto-coder.chat-初级入门指南.pdf_page4.png', './test_output/002-auto-coder.chat-初级入门指南.pdf_page5.png', './test_output/002-auto-coder.chat-初级入门指南.pdf_page6.png', './test_output/002-auto-coder.chat-初级入门指南.pdf_page7.png', './test_output/002-auto-coder.chat-初级入门指南.pdf_page8.png', './test_output/002-auto-coder.chat-初级入门指南.pdf_page9.png', './test_output/002-auto-coder.chat-初级入门指南.pdf_page10.png', './test_output/002-auto-coder.chat-初级入门指南.pdf_page11.png', './test_output/002-auto-coder.chat-初级入门指南.pdf_page12.png', './test_output/002-auto-coder.chat-初级入门指南.pdf_page13.png', './test_output/002-auto-coder.chat-初级入门指南.pdf_page14.png']\n",
      "图片分析结果: text='002-auto-coder.chat 初级入门指南\\n我们在上一篇介绍了如何安装 auto-coder.chat 回 Windows: auto-coder.chat 安装指南\\n MacOS/Linux 直接 pip install -U auto-coder 即可。测试过的 python 版本为：3.10/3.11\\n初始化设置\\n在 PowerShell/CMD 或者 VSCode 内置的 terminal 中输入如下指令（auto-coder.chat）：\\nPS C:\\\\Users\\\\Administrator\\\\projects\\\\auto-coder> auto-coder.chat\\n记得不要忘记了使用 conda activate auto-coder 切换到合适的环境虚拟环境哟。\\n第一次运行，系统会自动要求你提供一个大模型供应商（你后续可以改，比如用本地的模型或者其他第三方模型），此时会弹出一个对话框：' images=[ImageInfo(coordinates=[0.04, 0.38, 0.96, 0.59], text='命令行界面的截图', width=1000, height=250)] width=1000 height=1414\n"
     ]
    }
   ],
   "source": [
    "from autocoder.common.anything2img import Page\n",
    "# 测试 PDF 文件转换\n",
    "pdf_file = \"/Users/allwefantasy/Downloads/002-auto-coder.chat-初级入门指南.pdf\"  # 请确保测试目录下有这个文件\n",
    "if os.path.exists(pdf_file):\n",
    "    image_paths = converter.convert_pdf(pdf_file)\n",
    "    print(f\"转换后的图片路径: {image_paths}\")\n",
    "    \n",
    "    # 测试图片分析\n",
    "    for img_path in [image_paths[0]]:\n",
    "        page_info = converter.analyze_image.with_llm(vl_llm).with_return_type(Page).run(img_path)\n",
    "        print(f\"图片分析结果: {page_info}\")\n",
    "else:\n",
    "    print(f\"测试文件 {pdf_file} 不存在，跳过 PDF 测试\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 测试 DOCX 转换"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 测试 DOCX 文件转换\n",
    "docx_file = \"test.docx\"  # 请确保测试目录下有这个文件\n",
    "if os.path.exists(docx_file):\n",
    "    image_paths = converter.convert_docx(docx_file)\n",
    "    print(f\"转换后的图片路径: {image_paths}\")\n",
    "    \n",
    "    # 测试图片分析\n",
    "    for img_path in image_paths:\n",
    "        page_info = converter.analyze_image.with_llm(llm).with_return_type(Page).run(img_path)\n",
    "        print(f\"图片分析结果: {page_info}\")\n",
    "else:\n",
    "    print(f\"测试文件 {docx_file} 不存在，跳过 DOCX 测试\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 测试 Markdown 生成"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "ename": "JSONDecodeError",
     "evalue": "Invalid control character at: line 3 column 40 (char 42)",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mJSONDecodeError\u001b[0m                           Traceback (most recent call last)",
      "Cell \u001b[0;32mIn[4], line 2\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mjson\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[43mjson\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mloads\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\"\"\u001b[39;49m\n\u001b[1;32m      3\u001b[0m \u001b[38;5;124;43m{\u001b[39;49m\n\u001b[1;32m      4\u001b[0m \u001b[38;5;124;43m    \u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mtext\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43m: \u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43m002-auto-coder.chat 初级入门指南\u001b[39;49m\u001b[38;5;130;43;01m\\n\u001b[39;49;00m\u001b[38;5;130;43;01m\\n\u001b[39;49;00m\u001b[38;5;124;43m我们在上一篇介绍了如何安装 auto-coder.chat 回Windows: auto-coder.chat 安装指南\u001b[39;49m\u001b[38;5;130;43;01m\\n\u001b[39;49;00m\u001b[38;5;130;43;01m\\n\u001b[39;49;00m\u001b[38;5;124;43m MacOS/Linux 直接 pip install -U auto-coder 即可。测试过的 python 版本为： 3.10/3.11\u001b[39;49m\u001b[38;5;130;43;01m\\n\u001b[39;49;00m\u001b[38;5;130;43;01m\\n\u001b[39;49;00m\u001b[38;5;124;43m初始化设置\u001b[39;49m\u001b[38;5;130;43;01m\\n\u001b[39;49;00m\u001b[38;5;130;43;01m\\n\u001b[39;49;00m\u001b[38;5;124;43m在 PowerShell/CMD 或者 VSCode 内置的 terminal 中输入如下指令（auto-coder.chat）：\u001b[39;49m\u001b[38;5;130;43;01m\\n\u001b[39;49;00m\u001b[38;5;130;43;01m\\n\u001b[39;49;00m\u001b[38;5;124;43mPS C: \u001b[39;49m\u001b[38;5;130;43;01m\\\\\u001b[39;49;00m\u001b[38;5;124;43mUsers\u001b[39;49m\u001b[38;5;130;43;01m\\\\\u001b[39;49;00m\u001b[38;5;124;43mAdministrator\u001b[39;49m\u001b[38;5;130;43;01m\\\\\u001b[39;49;00m\u001b[38;5;124;43mprojects\u001b[39;49m\u001b[38;5;130;43;01m\\\\\u001b[39;49;00m\u001b[38;5;124;43mauto-coder> auto-coder.chat\u001b[39;49m\u001b[38;5;130;43;01m\\n\u001b[39;49;00m\u001b[38;5;130;43;01m\\n\u001b[39;49;00m\u001b[38;5;124;43m记得不要忘记了使用 conda activate auto-coder 切换到合适的环境虚拟环境哟。\u001b[39;49m\u001b[38;5;130;43;01m\\n\u001b[39;49;00m\u001b[38;5;130;43;01m\\n\u001b[39;49;00m\u001b[38;5;124;43m第一次运行，系统会自动要求你提供一个大模型供应商（你后续可以改，比如用本地的模型或者其他第三方模型），此时会弹出一个对话框：\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43m,\u001b[39;49m\n\u001b[1;32m      5\u001b[0m \u001b[38;5;124;43m    \u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mimages\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43m: [\u001b[39;49m\n\u001b[1;32m      6\u001b[0m \u001b[38;5;124;43m        \u001b[39;49m\u001b[38;5;124;43m{\u001b[39;49m\n\u001b[1;32m      7\u001b[0m \u001b[38;5;124;43m            \u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mcoordinates\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43m: [0.05, 0.39, 0.95, 0.59],\u001b[39;49m\n\u001b[1;32m      8\u001b[0m \u001b[38;5;124;43m            \u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mtext\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43m: \u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43m对图片的描述\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\n\u001b[1;32m      9\u001b[0m \u001b[38;5;124;43m        }\u001b[39;49m\n\u001b[1;32m     10\u001b[0m \u001b[38;5;124;43m    ],\u001b[39;49m\n\u001b[1;32m     11\u001b[0m \u001b[38;5;124;43m    \u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mwidth\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43m: 页面宽度,\u001b[39;49m\n\u001b[1;32m     12\u001b[0m \u001b[38;5;124;43m    \u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mheight\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43m: 页面高度\u001b[39;49m\n\u001b[1;32m     13\u001b[0m \u001b[38;5;124;43m}\u001b[39;49m\n\u001b[1;32m     14\u001b[0m \u001b[38;5;124;43m\"\"\"\u001b[39;49m\u001b[43m)\u001b[49m\n",
      "File \u001b[0;32m/opt/miniconda3/envs/byzerllm/lib/python3.10/json/__init__.py:346\u001b[0m, in \u001b[0;36mloads\u001b[0;34m(s, cls, object_hook, parse_float, parse_int, parse_constant, object_pairs_hook, **kw)\u001b[0m\n\u001b[1;32m    341\u001b[0m     s \u001b[38;5;241m=\u001b[39m s\u001b[38;5;241m.\u001b[39mdecode(detect_encoding(s), \u001b[38;5;124m'\u001b[39m\u001b[38;5;124msurrogatepass\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m    343\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (\u001b[38;5;28mcls\u001b[39m \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m object_hook \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m\n\u001b[1;32m    344\u001b[0m         parse_int \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m parse_float \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m\n\u001b[1;32m    345\u001b[0m         parse_constant \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m object_pairs_hook \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m kw):\n\u001b[0;32m--> 346\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43m_default_decoder\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdecode\u001b[49m\u001b[43m(\u001b[49m\u001b[43ms\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    347\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mcls\u001b[39m \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m    348\u001b[0m     \u001b[38;5;28mcls\u001b[39m \u001b[38;5;241m=\u001b[39m JSONDecoder\n",
      "File \u001b[0;32m/opt/miniconda3/envs/byzerllm/lib/python3.10/json/decoder.py:337\u001b[0m, in \u001b[0;36mJSONDecoder.decode\u001b[0;34m(self, s, _w)\u001b[0m\n\u001b[1;32m    332\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mdecode\u001b[39m(\u001b[38;5;28mself\u001b[39m, s, _w\u001b[38;5;241m=\u001b[39mWHITESPACE\u001b[38;5;241m.\u001b[39mmatch):\n\u001b[1;32m    333\u001b[0m \u001b[38;5;250m    \u001b[39m\u001b[38;5;124;03m\"\"\"Return the Python representation of ``s`` (a ``str`` instance\u001b[39;00m\n\u001b[1;32m    334\u001b[0m \u001b[38;5;124;03m    containing a JSON document).\u001b[39;00m\n\u001b[1;32m    335\u001b[0m \n\u001b[1;32m    336\u001b[0m \u001b[38;5;124;03m    \"\"\"\u001b[39;00m\n\u001b[0;32m--> 337\u001b[0m     obj, end \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mraw_decode\u001b[49m\u001b[43m(\u001b[49m\u001b[43ms\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43midx\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m_w\u001b[49m\u001b[43m(\u001b[49m\u001b[43ms\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mend\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    338\u001b[0m     end \u001b[38;5;241m=\u001b[39m _w(s, end)\u001b[38;5;241m.\u001b[39mend()\n\u001b[1;32m    339\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m end \u001b[38;5;241m!=\u001b[39m \u001b[38;5;28mlen\u001b[39m(s):\n",
      "File \u001b[0;32m/opt/miniconda3/envs/byzerllm/lib/python3.10/json/decoder.py:353\u001b[0m, in \u001b[0;36mJSONDecoder.raw_decode\u001b[0;34m(self, s, idx)\u001b[0m\n\u001b[1;32m    344\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"Decode a JSON document from ``s`` (a ``str`` beginning with\u001b[39;00m\n\u001b[1;32m    345\u001b[0m \u001b[38;5;124;03ma JSON document) and return a 2-tuple of the Python\u001b[39;00m\n\u001b[1;32m    346\u001b[0m \u001b[38;5;124;03mrepresentation and the index in ``s`` where the document ended.\u001b[39;00m\n\u001b[0;32m   (...)\u001b[0m\n\u001b[1;32m    350\u001b[0m \n\u001b[1;32m    351\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m    352\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m--> 353\u001b[0m     obj, end \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mscan_once\u001b[49m\u001b[43m(\u001b[49m\u001b[43ms\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43midx\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    354\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mStopIteration\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m err:\n\u001b[1;32m    355\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m JSONDecodeError(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mExpecting value\u001b[39m\u001b[38;5;124m\"\u001b[39m, s, err\u001b[38;5;241m.\u001b[39mvalue) \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n",
      "\u001b[0;31mJSONDecodeError\u001b[0m: Invalid control character at: line 3 column 40 (char 42)"
     ]
    }
   ],
   "source": [
    "import json\n",
    "json.loads(\"\"\"\n",
    "{\n",
    "    \"text\": \"002-auto-coder.chat 初级入门指南\\n\\n我们在上一篇介绍了如何安装 auto-coder.chat 回Windows: auto-coder.chat 安装指南\\n\\n MacOS/Linux 直接 pip install -U auto-coder 即可。测试过的 python 版本为： 3.10/3.11\\n\\n初始化设置\\n\\n在 PowerShell/CMD 或者 VSCode 内置的 terminal 中输入如下指令（auto-coder.chat）：\\n\\nPS C: \\\\Users\\\\Administrator\\\\projects\\\\auto-coder> auto-coder.chat\\n\\n记得不要忘记了使用 conda activate auto-coder 切换到合适的环境虚拟环境哟。\\n\\n第一次运行，系统会自动要求你提供一个大模型供应商（你后续可以改，比如用本地的模型或者其他第三方模型），此时会弹出一个对话框：\",\n",
    "    \"images\": [\n",
    "        {\n",
    "            \"coordinates\": [0.05, 0.39, 0.95, 0.59],\n",
    "            \"text\": \"对图片的描述\"\n",
    "        }\n",
    "    ],\n",
    "    \"width\": 页面宽度,\n",
    "    \"height\": 页面高度\n",
    "}\n",
    "\"\"\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 清理测试环境"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 删除测试输出目录\n",
    "import shutil\n",
    "shutil.rmtree(test_output_dir)\n",
    "print(f\"已删除测试输出目录: {test_output_dir}\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
